package dormouse.fx;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javafx.concurrent.Task;
import javafx.event.Event;
import javafx.event.EventHandler;

/**
 * This mixin is used to add event support to any class.  To use it, simply instantiate it
 * within a class and add listeners as appropriate.
 * 
 * @param <T>
 *            The event type
 */
public class EventMixin<T extends Event> {

	/** The list of listeners subscribing to these events. */
	private List<EventHandler<T>> listenerList = new ArrayList<EventHandler<T>>();

	/** The executor used to notify event listeners. */
	private ExecutorService eventExec = Executors.newFixedThreadPool(5);

	/**
	 * Constructor.
	 */
	public EventMixin() {

	}

	/**
	 * Adds an event listener.
	 * 
	 * @param listener
	 *            the listener to be added.
	 */
	public void addListener(EventHandler<T> listener) {
		listenerList.add(listener);
	}

	/**
	 * Removes an event listener.
	 * 
	 * @param listener
	 *            the listener to be removed.
	 */
	public void removeListener(EventHandler<T> listener) {
		listenerList.remove(listener);
	}

	/**
	 * Notifies the listeners.
	 * 
	 * @param event
	 *            to be broadcast to the listeners
	 */
	public void notifyListeners(T event) {

		for (EventHandler<T> handler : listenerList) {
			Notifier notifier = new Notifier(handler, event);
			eventExec.submit(notifier);
		}

	}

	/**
	 * This task is responsible for notifying event handlers
	 * 
	 */
	class Notifier extends Task<Void> {

		private EventHandler<T> handler;
		private T event;

		public Notifier(EventHandler<T> handler, T event) {
			this.handler = handler;
		}

		@Override
		protected Void call() throws Exception {

			handler.handle(event);
			return null;
		}

	}

}
